import { TIME_UNITS } from '../../../types/constants'

export type HourlyDistributionFormatType = '24h' | '12h' | 'simple'
export interface HourlyDistributionResult {
  startHour?: number
  filterInvalid?: boolean
  labelFormat?: HourlyDistributionFormatType
}

export type elapsedTimeFormatType = 'auto' | 'seconds' | 'minutes' | 'humanized'

/**
 * 时间日期工具类
 */
export class TimeUtils {
  /**
   * 解析时间戳
   */
  static parseTimestamp(timestamp: string | undefined): number {
    if (!timestamp)
      return Date.now()

    return new Date(timestamp).getTime()
  }

  /**
   * 按年格式化
   */
  static formatYear(timestamp: string | number): string {
    const date = new Date(timestamp)

    return `${date.getFullYear()}`
  }

  /**
   * 按年月格式化
   */
  static formatYearMonth(timestamp: string | number): string {
    const date = new Date(timestamp)

    return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`
  }

  /**
   * 获取当前时间，可选高精度模式（performance.now()）
   */
  static getCurrentTime(useHighPrecision: boolean = false): number {
    if (useHighPrecision && typeof performance !== 'undefined' && performance.now)
      return performance.now()

    return Date.now()
  }

  /**
   * 获取当前日期字符串 (YYYY-MM-DD)
   * @returns 格式化的日期字符串
   */
  static getCurrentDateString(): string {
    const date = new Date()
    const year = date.getFullYear()
    const month = String(date.getMonth() + 1).padStart(2, '0')
    const day = String(date.getDate()).padStart(2, '0')
    return `${year}-${month}-${day}`
  }

  /**
   * 将日期转换为语义化描述
   * @param date 日期对象或时间戳
   * @returns 语义化时间描述
   */
  static formatRelativeTime(date: Date | number | string): string {
    // 处理空值或无效日期
    if (!date || (typeof date === 'string' && date.trim() === '')) {
      return '未知'
    }

    const now = new Date()
    let targetDate: Date

    // 统一日期解析逻辑
    if (typeof date === 'string') {
      // 处理不带时间的ISO格式日期字符串（如"2024-08-07"）
      targetDate = date.includes('T') ? new Date(date) : new Date(`${date}T00:00:00`)
    }
    else {
      targetDate = new Date(date)
    }

    // 验证日期有效性
    if (Number.isNaN(targetDate.getTime())) {
      return '无效日期'
    }

    const timeDiff = now.getTime() - targetDate.getTime()

    // 处理未来时间
    if (timeDiff < 0) {
      return '未来时间'
    }

    // 计算时间差
    const seconds = Math.floor(timeDiff / 1000)
    const minutes = Math.floor(seconds / 60)
    const hours = Math.floor(minutes / 60)
    const days = Math.floor(hours / 24)

    // 精确计算年/月
    const fullYears = now.getFullYear() - targetDate.getFullYear()
    const fullMonths = (now.getMonth() + fullYears * 12) - targetDate.getMonth()

    // 判断是否需要减少一年（如果目标月份还未到）
    const adjustedYears = now.getMonth() < targetDate.getMonth()
      || (now.getMonth() === targetDate.getMonth() && now.getDate() < targetDate.getDate())
      ? fullYears - 1
      : fullYears

    if (adjustedYears >= 1) {
      return `${adjustedYears}年前`
    }
    if (fullMonths >= 1) {
      return `${fullMonths}个月前`
    }
    if (days >= 7) {
      const weeks = Math.floor(days / 7)
      return `${weeks}周前`
    }
    if (days >= 1) {
      return `${days}天前`
    }
    if (hours >= 1) {
      return `${hours}小时前`
    }
    if (minutes >= 1) {
      return `${minutes}分钟前`
    }
    if (seconds >= 10) {
      return `${seconds}秒前`
    }
    return '刚刚'
  }

  /**
   * 获取完整的时间描述
   * @param date 日期
   * @returns 完整的时间描述
   */
  static getFullTimeDescription(date: Date | number | string): string {
    const formattedDate = new Date(date).toLocaleString()
    const relativeTime = this.formatRelativeTime(date)
    return `${formattedDate} (${relativeTime})`
  }

  /**
   * 格式化时间为字符串
   */
  static formatTime(date: Date | number | string): string {
    let dateObj: Date

    if (date instanceof Date) {
      dateObj = date
    }
    else if (typeof date === 'number') {
      dateObj = new Date(date)
    }
    else if (typeof date === 'string') {
      dateObj = new Date(date)

      // 检查日期是否有效
      if (Number.isNaN(dateObj.getTime())) {
        return 'Invalid Date'
      }
    }
    else {
      return 'Invalid Date'
    }

    return dateObj.toLocaleTimeString('zh-CN', {
      hour12: false,
      year: 'numeric',
      month: '2-digit',
      day: '2-digit',
      hour: '2-digit',
      minute: '2-digit',
      second: '2-digit',
    })
  }

  /**
   * 格式化日期时间
   */
  static formatDateTime(isoValue: string | number): string {
    const date = new Date(isoValue)
    return date.toLocaleDateString('zh-CN', {
      month: 'short',
      day: 'numeric',
      hour: '2-digit',
      minute: '2-digit',
    })
  }

  /**
   * 计算并格式化运行时间
   * @param startTime 开始时间
   * @returns 格式化的时间字符串，如 "3天5时20分15秒"
   */
  static runTime(startTime: Date): string {
    const now = Date.now()
    const elapsedMs = now - startTime.getTime()

    // 定义时间单位常量（毫秒）
    const MS_PER_SECOND = 1000
    const MS_PER_MINUTE = 60 * MS_PER_SECOND
    const MS_PER_HOUR = 60 * MS_PER_MINUTE
    const MS_PER_DAY = 24 * MS_PER_HOUR

    // 计算各时间单位
    const days = Math.floor(elapsedMs / MS_PER_DAY)
    const hours = Math.floor((elapsedMs % MS_PER_DAY) / MS_PER_HOUR)
    const minutes = Math.floor((elapsedMs % MS_PER_HOUR) / MS_PER_MINUTE)
    const seconds = Math.floor((elapsedMs % MS_PER_MINUTE) / MS_PER_SECOND)

    return `${days}天${hours}时${minutes}分${seconds}秒`
  }

  /**
   * 校验文本是否满足时间格式要求
   */
  static isValidTimeText(text: string): boolean {
    // 合并所有时间格式的正则表达式
    return /\d{4}[年-]\d{1,2}[月-]\d{1,2}日?|\d+(?:小时|分钟|[秒天周月年])前/.test(text)
  }

  /**
   * 校验文本是否满足'年月日'时间格式要求
   */
  static isValidDateText(text: string): boolean {
    // 合并所有时间格式的正则表达式
    return /\d{4}[年-]\d{1,2}[月-]\d{1,2}日?/.test(text)
  }

  /**
   * 将日期格式转换为相对时间
   * @param dateStr 日期字符串，格式为"YYYY年MM月DD日" 或 "YYYY-MM-DD"
   * @returns 相对时间字符串，如"3个月前"、"2年前"
   */
  static convertToRelativeTime(dateStr: string): string {
    // 解析日期
    const match = dateStr.match(/(\d{4})[年-](\d{1,2})[月-](\d{1,2})日?/)
    if (!match)
      return dateStr

    const year = Number.parseInt(match[1])
    const month = Number.parseInt(match[2])
    const day = Number.parseInt(match[3])

    // 创建日期对象
    const targetDate = new Date(year, month - 1, day)
    const currentDate = new Date()

    // 计算时间差（毫秒）
    const diffMs = currentDate.getTime() - targetDate.getTime()
    const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24))

    // 转换为相对时间
    if (diffDays >= 365) {
      const years = Math.floor(diffDays / 365)
      return `${years}年前`
    }
    else if (diffDays >= 30) {
      const months = Math.floor(diffDays / 30)
      return `${months}个月前`
    }
    else if (diffDays >= 1) {
      return `${diffDays}天前`
    }
    else {
      return '今天'
    }
  }

  /**
   * 时间间隔格式化
   * @param value 时间值
   * @param unit 时间单位 ('hours' | 'minutes' | 'days')
   * @param shortFormat 是否使用短格式（默认false）
   */
  static formatTimeInterval(
    value: number,
    unit: 'hours' | 'minutes' | 'days' | 'timestamp' = 'hours',
    shortFormat: boolean = false,
  ): string {
    // 转换为小时作为基准单位
    let hours: number

    switch (unit) {
      case 'timestamp': {
        hours = (Date.now() - value) / TIME_UNITS.COMMON.INTERVALS.ONE_HOUR
        break
      }
      case 'minutes':
        hours = value / 60
        break
      case 'days':
        hours = value * TIME_UNITS.HOURS.DAY
        break
      case 'hours':
      default:
        hours = value
        break
    }

    // 处理未来时间（时间戳大于当前时间）
    if (hours < 0) {
      return shortFormat ? '未来时间' : '未来的时间'
    }

    // 处理小于1分钟的情况
    if (hours < TIME_UNITS.HOURS.MINUTE) {
      const minutes = hours * 60
      if (minutes < 1) {
        const seconds = Math.floor(minutes * 60)
        return shortFormat ? `${seconds}秒` : `${seconds}秒钟`
      }
      const formattedMinutes = Math.floor(minutes)
      return shortFormat ? `${formattedMinutes}分钟` : `${formattedMinutes}分钟`
    }

    // 处理小于1小时的情况
    if (hours < TIME_UNITS.HOURS.HOUR) {
      const minutes = hours * 60
      const formattedMinutes = minutes.toFixed(minutes < 10 ? 1 : 0)
      return shortFormat ? `${formattedMinutes}分钟` : `${formattedMinutes}分钟`
    }

    // 处理小于1天的情况
    if (hours < TIME_UNITS.HOURS.DAY) {
      const formattedHours = hours.toFixed(hours < 10 ? 1 : 0)
      return shortFormat ? `${formattedHours}小时` : `${formattedHours}小时`
    }

    // 处理小于1周的情况
    if (hours < TIME_UNITS.HOURS.WEEK) {
      const days = hours / TIME_UNITS.HOURS.DAY
      const formattedDays = days.toFixed(days < 10 ? 1 : 0)
      return shortFormat ? `${formattedDays}天` : `${formattedDays}天`
    }

    // 处理小于1月的情况
    if (hours < TIME_UNITS.HOURS.MONTH) {
      const weeks = hours / TIME_UNITS.HOURS.WEEK
      const formattedWeeks = weeks.toFixed(weeks < 10 ? 1 : 0)
      return shortFormat ? `${formattedWeeks}周` : `${formattedWeeks}周`
    }

    // 处理小于1年的情况
    if (hours < TIME_UNITS.HOURS.YEAR) {
      const months = hours / TIME_UNITS.HOURS.MONTH
      const formattedMonths = months.toFixed(months < 10 ? 1 : 0)
      return shortFormat ? `${formattedMonths}个月` : `${formattedMonths}个月`
    }

    // 处理大于1年的情况
    const years = hours / TIME_UNITS.HOURS.YEAR
    const formattedYears = years.toFixed(years < 10 ? 1 : 0)
    return shortFormat ? `${formattedYears}年` : `${formattedYears}年`
  }

  /**
   * 从数组中提取最晚的时间
   */
  static getLatestTime(times: number[]): number | undefined {
    if (times.length === 0)
      return undefined

    return times.reduce((prev, current) => (prev > current ? prev : current))
  }

  /**
   * 计算时间间隔（天），向上取整
   */
  static calculateDurationDays(startDate: string | number, endDate: string | number): number {
    const start = new Date(startDate)
    const end = new Date(endDate)

    const startDay = this.resetToStartOfDay(start)
    const endDay = this.resetToStartOfDay(end)

    const diffMs = endDay.getTime() - startDay.getTime()

    return Math.ceil(diffMs / TIME_UNITS.COMMON.INTERVALS.ONE_DAY)
  }

  /**
   * 重置日期为当天的00:00:00.000
   */
  static resetToStartOfDay(date: Date): Date {
    return new Date(date.getFullYear(), date.getMonth(), date.getDate())
  }

  /**
   * 从日期数组中提取小时分布（返回对象格式）
   */
  static extractHourDistribution(
    dates: (string | Date | number)[],
    options: HourlyDistributionResult = {},
  ): Record<string, number> {
    const {
      startHour = 7,
      filterInvalid = true,
      labelFormat = '24h',
    } = options

    // 初始化24小时分布
    const hourlyCounts = Array.from<number>({ length: 24 }).fill(0)

    // 统计每个小时的数量
    dates.forEach((date) => {
      try {
        const dateObj = new Date(date)
        if (filterInvalid && Number.isNaN(dateObj.getTime())) {
          return
        }

        const hour = dateObj.getHours()
        hourlyCounts[hour] += 1
      }
      catch (error) {
        if (!filterInvalid) {
          console.warn('处理日期时出错:', error)
        }
      }
    })

    // 转换为对象格式，按指定起始时间排序
    return this.convertToHourObject(hourlyCounts, startHour, labelFormat)
  }

  /**
   * 将小时数组转换为对象格式
   */
  private static convertToHourObject(
    hourlyCounts: number[],
    startHour: number = 7,
    labelFormat: HourlyDistributionFormatType = '24h',
  ): Record<string, number> {
    const result: Record<string, number> = {}

    // 生成 24 小时标签并赋值
    for (let i = 0; i < 24; i++) {
      const hourIndex = (startHour + i) % 24
      const label = this.formatHourLabel(hourIndex, labelFormat)
      result[label] = hourlyCounts[hourIndex]
    }

    return result
  }

  /**
   * 格式化小时标签
   */
  private static formatHourLabel(hour: number, format: HourlyDistributionFormatType = '24h'): string {
    switch (format) {
      case '12h':
      { const period = hour < 12 ? 'AM' : 'PM'
        const hour12 = hour % 12 || 12
        return `${hour12}:00 ${period}` }

      case 'simple':
        return `${hour}时`

      case '24h':
      default:
        return `${hour.toString().padStart(2, '0')}:00`
    }
  }

  /**
   * 格式化运行时间
   */
  static formatElapsedTime(milliseconds: number, timeFormat: elapsedTimeFormatType = 'auto'): string {
    const seconds = Math.floor(milliseconds / 1000)
    const minutes = Math.floor(seconds / 60)
    const hours = Math.floor(minutes / 60)

    switch (timeFormat) {
      case 'seconds':
        return `${seconds}秒`
      case 'minutes':
        return `${minutes}分${seconds % 60}秒`
      case 'humanized':
        if (hours > 0) {
          return `${hours}小时${minutes % 60}分${seconds % 60}秒`
        }
        else if (minutes > 0) {
          return `${minutes}分${seconds % 60}秒`
        }
        else {
          return `${seconds}秒`
        }
      case 'auto':
      default:
        if (minutes >= 1) {
          return `${minutes}分${seconds % 60}秒`
        }
        else {
          return `${seconds}秒`
        }
    }
  }
}
